package ie.ucd.ABLE.MachineLearning;



//Simple moving window or "t-test" statistical analysis 

//of power measurements. 

//Inspired by great projects like the MIT NALM and many others

//Code scribbled by Anders Dalen and edited by Timm Teubner

//=========================================================================

//Appliance disaggregation variables

//=========================================================================

//Incoming values from energy measurements 

//(code not included here)

double measuredPower;

//Constants to compare step change to known values

const int minStateChange = 100; // Minimum 10W to be a state change

const int stateCangeTolerance = 100;

const int knownAppliances[] = {1400, 300, 1150};

const char* knownApplianceNames[] = {"Electric Kettle","Iron","Washing Machine"};

//Setting up window constants and variables

const byte windowSize = 10; // Has to be even (saves a loop)

double window[windowSize];

int stepCount = 0;

boolean beginFound = false;

double beginLevel = 0;

boolean switchEvent = false;

//Variables for t-test

int switchStart;

const double tValue = 2.8; // Sensitivity level for first step change

double sum1=0, sum2=0, s1=0, s2=0;

double x1Hat, x2Hat;

double t0 = 0;

double diff, denom, change;

void loop()

{    

	// Just for pointing out when start is found in log

	switchStart = 0;



	// tTesting  

	for (int i=0; i<windowSize-1; i++) {

		window[i] = window[i+1];

	}

	window[windowSize-1] = measuredPower;



	sum1=0; sum2=0;



	for (int i=0; i<windowSize/2; i++) {

		sum1 += window[i];

		sum2 += window[i + windowSize/2];

	}



	x1Hat = sum1 / (windowSize/2);

	x2Hat = sum2 / (windowSize/2);



	// 2. Calculating sum of squared deviation from mean

	s1 = 0; s2 = 0;

	for (int i=0; i < windowSize/2; i++) {

		s1 += (window[i]-x1Hat) * (window[i]-x1Hat);

		s2 += (window[i+ windowSize/2]-x2Hat) * (window[i+ windowSize/2]-x2Hat);  

	}



	// 3. Dividing squared deviations to get sample variance

	s1 = s1 / (windowSize/2-1) + 1; // adding +1 in order not to run into too high t-values when there is no standard deviation at all...

	s2 = s2 / (windowSize/2-1) + 1;



	// t-Test calculation

	diff = abs(x1Hat - x2Hat);

	denom = sqrt((s1 + s2) / (windowSize/2));

	t0 = diff / denom;



	// Finding the beginning of the step change

	if (t0 >= tValue && !beginFound) {

		beginLevel = x1Hat;

		beginFound = true;

		switchStart = 1;

	}



	if (t0 >= tValue && beginFound) {

		stepCount += 1;

	}



	// Finding the end of the step change and saving the change value

	if (t0 < tValue && beginFound) {

		change = x2Hat - beginLevel;

		switchEvent = true;

		beginFound = false;

	} else {

		change = 0;

	}

	// I haven't tested this part, just put it here as an example of how one might write out a recognized step

	if (change > minStateChange){

		for (int i = 0; i < 3; i++){

			if (change > knownAppliances[i] - stateCangeTolerance || 

					change < knownAppliances[i] + stateCangeTolerance){

				Serial.println(knownApplianceNames[i]);

			}

		}

	}

}  
